/*
 *  ActionAgent.cpp
 *  Milovo04alfa00
 *
 *  Created by Luca on 21/11/06.
 *  Copyright 2006 __MyCompanyName__. All rights reserved.
 *
 */

#include "MilovoTables.h"
#include <limits.h>

//bool InnovationWithoutGoal(MilinitParams &,  SystemParams &, Mil_Int , Agents *, Recipes *, Artifacts *, MilovoRandom &, int);
bool TryInnovation(MilinitParams &,  SystemParams &, SimulationParams &, Mil_Int , Agents *, Recipes *, Artifacts *, Requests *, 
						 MilovoRandom &, MilovoEnvironment &);
bool CheckThisRecipe(Mil_Int , Recipes *tmp_TabRecipes, Agents *tmp_TabAgents, Artifacts *tmp_TabArtifacts, Requests *tmp_TabRequests, MilovoRandom &, MilovoEnvironment &);
void ProduceThisRecipe(Mil_Int , Recipes *tmp_TabRecipes, Agents *tmp_TabAgents, Artifacts *tmp_TabArtifacts, SystemParams &, int);
bool CalcActivityThisAgent(SystemParams &, Mil_Int , Agents *, Recipes *, Artifacts *, int);
bool CheckForEvents(Events &, Agents *, Mil_Int , Recipes *, Artifacts *, SystemParams &, MilovoEnvironment &);
bool ProduceRecipesThisAgent(Agents *, Mil_Int , Recipes *, Artifacts *, Requests *, MilovoRandom &, SystemParams &, MilovoEnvironment &);
bool InsertThisInputInTableRequests(Mil_Int tmpNameRequested, Requests *tmpCurrenTabRequests, Mil_Int tmpIDAgentToAnalize, MilovoEnvironment &tmp_CurrentMiloEnv);
vector<Mil_Int> GetOrderRecipesThisAgent(Agents *tmpCurrentTabAgents, Mil_Int tmpCurrentIDAgentToAnalize, MilovoRandom &tmpCurrentMiloRand, 
																 MilovoEnvironment &tmpCurrentMiloEnv);
vector<Mil_Int> GetRecipesThisAgentInRandomOrder(Agents *tmpCurrentTabAgents, Mil_Int tmpCurrentIDAgentToAnalize, MilovoRandom &tmpCurrentMiloRand, 
																 MilovoEnvironment &tmpCurrentMiloEnv);

void ActionAgent(Mil_Int tmpIDAgentToAnalize, Agents *tmpTabAgents, Recipes *tmpTabRecipes, Artifacts *tmpTabArtifacts, 
					  ScaffoldingStructure *tmpTabScaffoldigStructure, Requests *tmpTabRequests, MilinitParams &tmpInitParam, 
					  SystemParams &tmpMilovoParam, SimulationParams &tmpSimulaParam, Events &tmpTabEvents, MilovoRandom &tmpMiloRand, 
					  MilovoEnvironment &tmpMiloEnv)
{
	Agents::iterator tmpAgentSelectedIter = tmpTabAgents->find(tmpIDAgentToAnalize);
	if((tmpMiloEnv.GetDebugLevel() >= 0) && (tmpAgentSelectedIter == tmpTabAgents->end()))
	{
		cout << "Error in ActionAgent function: cannot find an existing agent:" << tmpAgentSelectedIter->second.GetID() << endl;
		exit(EXIT_FAILURE);
	}
	if(tmpMiloEnv.GetDebugLevel() >= 1)
		cout << "Check for agent: " << tmpAgentSelectedIter->second.GetID() << " --------------- [Begin] ----------------" << endl;
	
	tmpAgentSelectedIter->second.SetNumTimeSelected(tmpAgentSelectedIter->second.GetNumTimeSelected() + 1);
	// if MaxRecipesAllowed > 0, the recipes with minor Status of Artifact output must e deleted
	if(tmpAgentSelectedIter->second.Style.GetMaxRecipesAllowed() > 0)
		DeleteRecipesWithLessArtifactsStatus(tmpAgentSelectedIter->second.GetID(), tmpTabAgents, tmpTabRecipes, tmpTabArtifacts, 
														 tmpMiloEnv.GetDebugLevel());
						
	// generate relationship of this agent
	GenerateRelationshipThisAgent(tmpIDAgentToAnalize, tmpTabAgents, tmpTabRecipes, tmpTabArtifacts, tmpMiloEnv.GetCurrentStep(), 
											tmpMiloEnv.GetDebugLevel());
	// if scaffolding is on This agent add scaff-friends with a certain probability
	if((tmpMilovoParam.GetScaffoldingMaxLevel() > 0) && (tmpMiloRand.GetDoubleRandom(0.0, 1.0) <= tmpAgentSelectedIter->second.Style.GetScaffProb()))
	{
		if(AddScaffoldingFriends(tmpIDAgentToAnalize, tmpTabAgents, tmpTabScaffoldigStructure, tmpMiloEnv.GetDebugLevel()) == true)
			SubscribeThisAgent(tmpIDAgentToAnalize, tmpTabScaffoldigStructure, tmpMilovoParam.GetScaffoldingMaxLevel(), 
									 tmpMiloRand, tmpMiloEnv.GetDebugLevel());
	}
	// check for events
	CheckForEvents(tmpTabEvents, tmpTabAgents, tmpIDAgentToAnalize, tmpTabRecipes, tmpTabArtifacts, tmpMilovoParam, tmpMiloEnv);
	// calculate votes given to friends of this agent
	CalcVotesThisAgent(tmpAgentSelectedIter->second.GetID(), tmpTabAgents, tmpMilovoParam, tmpMiloEnv.GetDebugLevel());
	// produce recipes of this agent
	ProduceRecipesThisAgent(tmpTabAgents, tmpIDAgentToAnalize, tmpTabRecipes, tmpTabArtifacts, tmpTabRequests, tmpMiloRand, tmpMilovoParam, tmpMiloEnv);
	// calculate activity of this agent
	bool FlagDeadActivity = CalcActivityThisAgent(tmpMilovoParam, tmpIDAgentToAnalize, tmpTabAgents, tmpTabRecipes, tmpTabArtifacts, tmpMiloEnv.GetDebugLevel());
	// if some recipe of this agent has status <= 0, it must be deleted
	list<Mil_Int>::iterator tmpIDLinkRecipeIter = tmpAgentSelectedIter->second.LinkRecipes.begin();
	bool FlagAgentWithoutRecipes = true;
	while(tmpIDLinkRecipeIter != tmpAgentSelectedIter->second.LinkRecipes.end())
	{
		Recipes::iterator tmpTabRecipesIter = tmpTabRecipes->find(*tmpIDLinkRecipeIter);
		Artifacts::iterator tmpTabArtifactsIter = tmpTabArtifacts->find(tmpTabRecipesIter->second.GetIDArtifactOutput());
		tmpIDLinkRecipeIter++;
		if((tmpTabRecipesIter->second.GetStatus() <= 0) || (tmpTabArtifactsIter->second.GetStatus() <= 0))
		{
			if(tmpMiloEnv.GetDebugLevel() >= 0)
			{
				if(tmpTabRecipesIter->second.GetStatus() <= 0)
					tmpMiloEnv.SetNumRecipesDeadByProduction(tmpMiloEnv.GetNumRecipesDeadByProduction() + 1);
				if(tmpTabArtifactsIter->second.GetStatus() <= 0)
					tmpMiloEnv.SetNumRecipesDeadByMarket(tmpMiloEnv.GetNumRecipesDeadByMarket() + 1);
			}
			KillThisRecipe(tmpTabRecipesIter->second.GetID(), tmpTabRecipes, tmpTabArtifacts, tmpTabAgents, tmpMiloEnv.GetDebugLevel());
		}
		else FlagAgentWithoutRecipes = false;
	}
	// if this agent has almost one recipe, it may try to create a new recipe
	if((FlagAgentWithoutRecipes == false) && (FlagDeadActivity == false))
	{
		Mil_Double tmpInnoRand = tmpMiloRand.GetDoubleRandom(0.0, 1.0);
		if(tmpInnoRand <= tmpAgentSelectedIter->second.Style.GetProbImitation())
		{
			if(TryInnovation(tmpInitParam, tmpMilovoParam, tmpSimulaParam, tmpAgentSelectedIter->second.GetID(), tmpTabAgents, tmpTabRecipes, 
										 tmpTabArtifacts, tmpTabRequests, tmpMiloRand, tmpMiloEnv) == true)
				tmpMiloEnv.SetNumInnovationSucceded(tmpMiloEnv.GetNumInnovationSucceded() + 1);
			else tmpMiloEnv.SetNumInnovationFailed(tmpMiloEnv.GetNumInnovationFailed() + 1);
		}
	}
	// else this agent must be killed
	else 
	{
		if(FlagDeadActivity == true)
			tmpMiloEnv.SetNumAgentsDeadByMarket(tmpMiloEnv.GetNumAgentsDeadByMarket() + 1);
		if(FlagAgentWithoutRecipes == true)
			tmpMiloEnv.SetNumAgentsDeadByZeroRecipes(tmpMiloEnv.GetNumAgentsDeadByZeroRecipes() + 1);
		KillThisAgent(tmpAgentSelectedIter->second.GetID(), tmpTabAgents, tmpTabRecipes, tmpTabArtifacts, tmpMiloEnv.GetDebugLevel());
	}
	
	if(tmpMiloEnv.GetDebugLevel())
		cout << "Check for agent: " << tmpAgentSelectedIter->second.GetID() << " --------------- [End] ----------------" << endl;
}

bool CheckThisRecipe(Mil_Int tmpIDRecipeToAnalize, Recipes *tmp_TabRecipes, Agents *tmp_TabAgents, Artifacts *tmp_TabArtifacts, 
							Requests *tmp_TabRequests, MilovoRandom &tmp_MiloRand, MilovoEnvironment &tmpCurrentMiloEnv)
{
//	cout << "\t -- Check IDRecipe: " << tmpIDRecipeToAnalize << endl;
	Recipes::iterator tmp_TabRecipesIter = tmp_TabRecipes->find(tmpIDRecipeToAnalize);
	if((tmpCurrentMiloEnv.GetDebugLevel() >= 0) && (tmp_TabRecipesIter == tmp_TabRecipes->end()))
	{
		cout << "Error in CheckThisRecipe function: cannot find tmp_TabRecipesIter in tmp_TabRecipes" << endl;
		exit(EXIT_FAILURE);
	}
	if(tmpCurrentMiloEnv.GetDebugLevel() >= 1)
		cout << "CheckThisRecipe [begin]" << endl;
	
	tmp_TabRecipesIter->second.SetCanProduce(true);
	list<Mil_Int>::iterator LinksIDArtifactsIter = tmp_TabRecipesIter->second.LinksIDArtifacts.begin();
	list<Mil_Int>::iterator LinksNameArtifactsIter = tmp_TabRecipesIter->second.LinksNameArtifacts.begin();
	if((tmpCurrentMiloEnv.GetDebugLevel() >= 2) && 
		((LinksIDArtifactsIter == tmp_TabRecipesIter->second.LinksIDArtifacts.end()) ||
		 (LinksNameArtifactsIter == tmp_TabRecipesIter->second.LinksNameArtifacts.end())))
	{
		cout << "LinksIDArtifactsIter == tmp_TabRecipesIter->second.LinksIDArtifacts.end() or " << endl;	
		cout << "LinksNameArtifactsIter = tmp_TabRecipesIter->second.LinksNameArtifacts.end()" << endl;
		exit(EXIT_FAILURE);
	}
	
	while((LinksIDArtifactsIter != tmp_TabRecipesIter->second.LinksIDArtifacts.end()) && 
			(LinksNameArtifactsIter != tmp_TabRecipesIter->second.LinksNameArtifacts.end()) &&
			(tmp_TabRecipesIter->second.GetCanProduce() == true))
	{
		// first we check if this input exist in TabArtifacts. If not, flag recipe not producible
		Artifacts::iterator tmp_TabArtifactsIter = tmp_TabArtifacts->find(*LinksIDArtifactsIter);
		if(tmpCurrentMiloEnv.GetDebugLevel() >= 2)
		{
			Mil_Int tmpIDArtifactToPrint = *LinksIDArtifactsIter;
			cout << "Check for IDArt " << tmpIDArtifactToPrint << " of IDRecipe " << tmp_TabRecipesIter->second.GetID() << " ... " << endl;
		}
		Mil_Int HowManyCopyThisArtifactInRecipe = 0;
		if(tmp_TabArtifactsIter != tmp_TabArtifacts->end())
		{
			if((tmpCurrentMiloEnv.GetDebugLevel() >= 0) && (tmp_TabArtifactsIter->second.GetIDAgentOwner() == tmp_TabRecipesIter->second.GetIDAgentOwner()))
			{
				cout << "Error in CheckThisRecipe function: This input: " << tmp_TabArtifactsIter->second.GetID() << " is produced by agent: " << tmp_TabRecipesIter->second.GetIDAgentOwner() << endl;
				exit(EXIT_FAILURE);
			}

			HowManyCopyThisArtifactInRecipe = GetHowManyCopyThisArtifactInRecipe(tmp_TabArtifactsIter->second.GetID(), tmp_TabArtifacts, 
																										tmp_TabRecipesIter->second.GetID(), tmp_TabRecipes, 
																										tmpCurrentMiloEnv.GetDebugLevel());
		}
		
		Agents::iterator tmp_TabAgentsIter = tmp_TabAgents->find(tmp_TabRecipesIter->second.GetIDAgentOwner());
		if((tmpCurrentMiloEnv.GetDebugLevel() >= 0) && (tmp_TabAgentsIter == tmp_TabAgents->end()))
		{
			cout << "Error in CheckThisRecipe function: cannot find tmp_TabAgentsIter in tmp_TabAgents" << endl;
			exit(EXIT_FAILURE);
		}
		
		if((tmp_TabArtifactsIter == tmp_TabArtifacts->end()) || (tmp_TabArtifactsIter->second.GetAmount() < HowManyCopyThisArtifactInRecipe) ||
			(tmp_MiloRand.GetDoubleRandom(0.0, 1.0) <= tmp_TabAgentsIter->second.Style.GetUseSuppliersChange()))
		{
			if(tmpCurrentMiloEnv.GetDebugLevel() >= 2)
				cout << "Insufficient Amount or artifact not found: " << tmp_TabArtifactsIter->second.GetAmount() << endl;
			Mil_Int tmpIDInputToSubstitute = *LinksIDArtifactsIter;
			Mil_Int tmpNameInputToSubstitute = *LinksNameArtifactsIter;
			Mil_Int tmpIDArtifactSubstitute;
			if(tmp_TabAgentsIter->second.Style.GetChangeSupplierMethod() == 1)
			{
				tmpIDArtifactSubstitute = FindArtifactSubstitutePreferential(tmp_TabArtifacts, tmp_TabAgents, tmp_TabRecipes, tmp_TabRecipesIter->second.GetID(), 
																								 tmpIDInputToSubstitute, tmpNameInputToSubstitute, HowManyCopyThisArtifactInRecipe, 
																								 tmp_TabRecipesIter->second.GetIDAgentOwner(), tmpCurrentMiloEnv.GetDebugLevel());
			}
			else
			{
				tmpIDArtifactSubstitute = FindArtifactSubstitute(tmp_TabArtifacts, tmp_TabAgents, tmp_TabRecipes, tmp_TabRecipesIter->second.GetID(), 
																				 tmpIDInputToSubstitute, tmpNameInputToSubstitute, HowManyCopyThisArtifactInRecipe, 
																				 tmp_TabRecipesIter->second.GetIDAgentOwner(), tmp_MiloRand, tmpCurrentMiloEnv.GetDebugLevel());
			}
			
			if(tmpIDArtifactSubstitute == tmpIDInputToSubstitute)
			{
				tmp_TabRecipesIter->second.SetCanProduce(false);
				if(tmp_TabAgentsIter->second.Style.GetProbGoalFromRequest() >= 0.0)
					InsertThisInputInTableRequests(tmpNameInputToSubstitute, tmp_TabRequests, tmp_TabRecipesIter->second.GetIDAgentOwner(), tmpCurrentMiloEnv);
			}
			else 
			{
				Artifacts::iterator tmpIDArtifactSubstituteIter = tmp_TabArtifacts->find(tmpIDArtifactSubstitute);
				if((tmpCurrentMiloEnv.GetDebugLevel() >= 0) && (tmpIDArtifactSubstituteIter == tmp_TabArtifacts->end()))
				{
					cout << "Error in CheckThisRecipe function: cannot find tmpIDArtifactSubstitute in tmp_TabArtifacts" << endl;
					exit(EXIT_FAILURE);
				}

				if(tmpIDArtifactSubstituteIter->second.GetAmount() <= 0)
				{
					cout << "tmpIDArtifactSubstituteIter->second.GetAmount <= 0: " << tmpIDArtifactSubstituteIter->second.GetAmount() << endl;
					exit(EXIT_FAILURE);
				}
				
				*LinksIDArtifactsIter = tmpIDArtifactSubstituteIter->second.GetID();
				*LinksNameArtifactsIter = tmpIDArtifactSubstituteIter->second.GetName();
				tmp_TabRecipesIter->second.SetCanProduce(true);
			}
		}
		LinksIDArtifactsIter++;
		LinksNameArtifactsIter++;
	}
	if(tmpCurrentMiloEnv.GetDebugLevel() >= 1)
		cout << "CheckThisRecipe [end]" << endl;

	return(tmp_TabRecipesIter->second.GetCanProduce());
}

bool ProduceRecipesThisAgent(Agents *tmp_TabAgents, Mil_Int tmp_IDAgentToAnalize, Recipes *tmp_TabRecipes, Artifacts *tmp_TabArtifacts, 
							 Requests *tmp_TabRequests, MilovoRandom &tmp_MiloRand, SystemParams &tmp_MilovoParam, 
							 MilovoEnvironment &tmp_MiloEnv)
{
	Agents::iterator tmp_AgentSelectedIter = tmp_TabAgents->find(tmp_IDAgentToAnalize);
	if((tmp_MiloEnv.GetDebugLevel() >= 0) && (tmp_AgentSelectedIter == tmp_TabAgents->end()))
	{
		cout << "Error in ProduceRecipesThisAgent function: cannot find an existing agent:" << tmp_AgentSelectedIter->second.GetID() << endl;
		exit(EXIT_FAILURE);
	}
		
	vector<Mil_Int> VectRecipesThisAgents = GetOrderRecipesThisAgent(tmp_TabAgents, tmp_IDAgentToAnalize, tmp_MiloRand, tmp_MiloEnv);

	for(vector<Mil_Int>::iterator LinkRecipesIter = VectRecipesThisAgents.begin(); LinkRecipesIter != VectRecipesThisAgents.end(); LinkRecipesIter++)
	{
		Recipes::iterator tmp_TabRecipesIter = tmp_TabRecipes->find(*LinkRecipesIter);
		if((tmp_MiloEnv.GetDebugLevel() >= 0) && (tmp_TabRecipesIter == tmp_TabRecipes->end()))
		{
			Mil_Int tmpLinkIDRecipe = *LinkRecipesIter;
			cout << "Error in producing a exist recipe (ActionAgent function): Ag" << tmp_AgentSelectedIter->second.GetID() << " -> " << tmpLinkIDRecipe << endl;
			exit(EXIT_FAILURE);
		}
		
		if(tmp_MiloEnv.GetDebugLevel() >= 2)
			cout << "Start to analize recipe: " << tmp_TabRecipesIter->second.GetID() << endl;
		// check if the amount of output of this recipe is "empty". If this, add of one
		// unit the number of time that agent produce this recipe.
		Artifacts::iterator tmp_TabArtifactsIter = tmp_TabArtifacts->find(tmp_TabRecipesIter->second.GetIDArtifactOutput());
		if((tmp_MiloEnv.GetDebugLevel() >= 0) && (tmp_TabArtifactsIter->second.GetAmount() < 0))
		{
			cout << "Error in ProduceRecipesThisAgent function: tmp_TabArtifactsIter->second.GetAmount() < 0: " << tmp_TabArtifactsIter->second.GetAmount() << endl;
			exit(EXIT_FAILURE);
		}
		
		if(tmp_TabArtifactsIter->second.GetAmount() < tmp_TabArtifactsIter->second.GetAmountCeil())
		{
			if(tmp_TabRecipesIter->second.GetNProduce() < tmp_AgentSelectedIter->second.Style.GetNProduceCeil())
				tmp_TabRecipesIter->second.SetNProduce(tmp_TabRecipesIter->second.GetNProduce() + 1);
		}
		else
		{
			if(tmp_TabRecipesIter->second.GetNProduce() > tmp_AgentSelectedIter->second.Style.GetNProduceFloor())
				tmp_TabRecipesIter->second.SetNProduce(tmp_TabRecipesIter->second.GetNProduce() - 1);
		}
		
		bool FlagProduceThisRecipe = true;
		Mil_Int NProduceIndex = 0;
		while((FlagProduceThisRecipe == true) && (NProduceIndex < tmp_TabRecipesIter->second.GetNProduce()))
		{
			FlagProduceThisRecipe = CheckThisRecipe(tmp_TabRecipesIter->second.GetID(), tmp_TabRecipes, tmp_TabAgents, tmp_TabArtifacts, 
																 tmp_TabRequests, tmp_MiloRand, tmp_MiloEnv);
			if(FlagProduceThisRecipe == true)
				ProduceThisRecipe(tmp_TabRecipesIter->second.GetID(), tmp_TabRecipes, tmp_TabAgents, tmp_TabArtifacts, 
										tmp_MilovoParam, tmp_MiloEnv.GetDebugLevel());
			else 
			{
				if(NProduceIndex == 0)
					tmp_TabRecipesIter->second.SetStatus(tmp_TabRecipesIter->second.GetStatus() - 1);
			}
			NProduceIndex++;
		}
			
		if(tmp_MiloEnv.GetDebugLevel() >= 2)
			cout << "End to analize recipe: " << tmp_TabRecipesIter->second.GetID() << endl;
	}
	
	return true;
}

void ProduceThisRecipe(Mil_Int tmpIDRecipeToAnalize, Recipes *tmp_TabRecipes, Agents *tmp_TabAgents, Artifacts *tmp_TabArtifacts, 
							  SystemParams &tmp_MilovoParam, int tmp_DebugLevel)
{
	Recipes::iterator tmp_TabRecipesIter = tmp_TabRecipes->find(tmpIDRecipeToAnalize);
	if((tmp_DebugLevel >= 0) && (tmp_TabRecipesIter == tmp_TabRecipes->end()))
	{
		cout << "Error in ProduceThisRecipe function: cannot find tmp_TabRecipesIter in tmp_TabRecipes: " << tmpIDRecipeToAnalize << endl;
		exit(EXIT_FAILURE);
	}
	if(tmp_DebugLevel >= 1)
		cout << "ProduceThisRecipe [begin]" << endl;
	
	for(list<Mil_Int>::iterator LinksIDArtifactsIter = tmp_TabRecipesIter->second.LinksIDArtifacts.begin(); LinksIDArtifactsIter != tmp_TabRecipesIter->second.LinksIDArtifacts.end(); LinksIDArtifactsIter++)
	{
		Artifacts::iterator tmpInputArtifactIter = tmp_TabArtifacts->find(*LinksIDArtifactsIter);
		if((tmp_DebugLevel >= 0) && (tmpInputArtifactIter == tmp_TabArtifacts->end()))
		{
			Mil_Int tmpInputIDArtifact = *LinksIDArtifactsIter;
			cout << "Error in ProduceThisRecipe function: cannot find tmpInputArtifactIter in tmp_TabArtifacts: " << tmpInputIDArtifact << endl;
			exit(EXIT_FAILURE);
		}
		// increase the buyers number of this artifact
		tmpInputArtifactIter->second.SetNumBuyers(tmpInputArtifactIter->second.GetNumBuyers() + 1);
		// decrease the amount level of this artifact
		tmpInputArtifactIter->second.SetAmount(tmpInputArtifactIter->second.GetAmount() - 1);
		if((tmp_DebugLevel >= 0) && (tmpInputArtifactIter->second.GetAmount() < 0))
		{
			cout << "Error in ProduceThisRecipe function: tmpInputArtifactIter->second.GetAmount() < 0: " << endl;
			cout << "\tIDInput:" << tmpInputArtifactIter->second.GetID() << "\tAmount: " << tmpInputArtifactIter->second.GetAmount() << endl;
			exit(EXIT_FAILURE);
		}
		// set this input artifact to max status value
		tmpInputArtifactIter->second.SetStatus(tmp_MilovoParam.GetMaxLifeArtifacts());
		// Get the agent owner this input artifact, for increasing the DeltaTransaction parameter about it of this agent
		Mil_Int tmpIDAgentOwnerThisInput = tmpInputArtifactIter->second.GetIDAgentOwner();
		// Get the agent owner this recipe, and searching for agent owner artifact to increase DeltaTransaction
		Agents::iterator tmp_TabAgentsIter = tmp_TabAgents->find(tmp_TabRecipesIter->second.GetIDAgentOwner());
		if((tmp_DebugLevel >= 0) && (tmp_TabAgentsIter == tmp_TabAgents->end()))
		{
			cout << "Error in ProduceThisRecipe function: cannot find tmp_TabAgentsIter in tmp_TabAgents: " << tmp_TabRecipesIter->second.GetIDAgentOwner() << endl;
			exit(EXIT_FAILURE);
		}
		// serching for friend in relationship table
		Relationships::iterator TabRelationshipsIter = tmp_TabAgentsIter->second.TabRelationships.find(tmpIDAgentOwnerThisInput);
		if((tmp_DebugLevel >= 0) && (TabRelationshipsIter == tmp_TabAgentsIter->second.TabRelationships.end()))
		{
			cout << "Error in ProduceThisRecipe function: cannot find TabRelationshipsIter in tmp_TabAgentsIter->second.TabRelationships: " << tmpIDAgentOwnerThisInput << endl;
			exit(EXIT_FAILURE);
		}
		// increase the DeltaTransaction value
		TabRelationshipsIter->second.SetDeltaTransactions(TabRelationshipsIter->second.GetDeltaTransactions() + 1);
		// increase the amount level of artifact output
		Artifacts::iterator tmpArtifactOutputIter = tmp_TabArtifacts->find(tmp_TabRecipesIter->second.GetIDArtifactOutput());
		if((tmp_DebugLevel >= 0) && (tmpArtifactOutputIter == tmp_TabArtifacts->end()))
		{
			cout << "Error in ProduceThisRecipe function: cannot find tmpArtifactOutputIter in tmp_TabArtifacts" << endl;
			exit(EXIT_FAILURE);
		}
		tmpArtifactOutputIter->second.SetAmount(tmpArtifactOutputIter->second.GetAmount() + 1);
		// set this recipe to the max status value
		tmp_TabRecipesIter->second.SetStatus(tmp_MilovoParam.GetMaxLifeRecipes());
		if(tmp_DebugLevel >= 2)
			cout << "Produce RecipeID " << tmp_TabRecipesIter->second.GetID() << " Status: " << tmp_TabRecipesIter->second.GetStatus() << " OutArtID: " << tmpArtifactOutputIter->second.GetID() << " AmountArtOut: " << tmpArtifactOutputIter->second.GetAmount() << endl; 
	}
	
	if(tmp_DebugLevel >= 1)
		cout << "ProduceThisRecipe [end]" << endl;
}

bool CalcActivityThisAgent(SystemParams &tmp_MilovoParam, Mil_Int tmp_IDAgentToAnalize, Agents *tmp_TabAgents, Recipes *tmp_TabRecipes, 
									Artifacts *tmp_TabArtifacts, int tmp_DebugLevel)
{
	bool FlagKillThisAgent = false;
	Agents::iterator tmp_TabAgentsIter = tmp_TabAgents->find(tmp_IDAgentToAnalize);
	if((tmp_DebugLevel >= 0) && (tmp_TabAgentsIter == tmp_TabAgents->end()))
	{
		cout << "Error in CalcActivityThisAgent function: cannot find tmp_TabAgentsIter in tmp_TabAgents: "<< tmp_IDAgentToAnalize << endl;
		exit(EXIT_FAILURE);
	}
	if(tmp_DebugLevel >= 1)
		cout << "CalcActivityThisAgent [begin]" << endl;

	Mil_Int NumSoldArtifactsThisAgent = 0;
	Mil_Double CostRecipes = 0.0;
	for(list<Mil_Int>::iterator LinkRecipesIter = tmp_TabAgentsIter->second.LinkRecipes.begin(); LinkRecipesIter != tmp_TabAgentsIter->second.LinkRecipes.end(); LinkRecipesIter++)
	{
		Recipes::iterator tmp_TabRecipesIter = tmp_TabRecipes->find(*LinkRecipesIter);
		if((tmp_DebugLevel >= 0) && (tmp_TabRecipesIter == tmp_TabRecipes->end()))
		{
			Mil_Int IDRecipesNotFound = *LinkRecipesIter;
			cout << "Error in CalcActivityThisAgent function: cannot find tmp_TabRecipesIter in tmp_TabRecipes: "<< IDRecipesNotFound << endl;
			exit(EXIT_FAILURE);
		}
		if(tmp_TabRecipesIter->second.GetStatus() == tmp_MilovoParam.GetMaxLifeRecipes())
			CostRecipes += tmp_TabRecipesIter->second.GetNProduce() * tmp_MilovoParam.GetCostRecipes();
		
		Artifacts::iterator tmp_TabArtifactsIter = tmp_TabArtifacts->find(tmp_TabRecipesIter->second.GetIDArtifactOutput());
		if((tmp_DebugLevel >= 0) && (tmp_TabArtifactsIter == tmp_TabArtifacts->end()))
		{
			cout << "Error in CalcActivityThisAgent function: cannot find tmp_TabArtifactsIter in tmp_TabArtifacts: "<< tmp_TabRecipesIter->second.GetIDArtifactOutput() << endl;
			exit(EXIT_FAILURE);
		}
		NumSoldArtifactsThisAgent += tmp_TabArtifactsIter->second.GetNumBuyers();
	}
	Mil_Double OldActivity = tmp_TabAgentsIter->second.GetActivity();
	Mil_Double tmpDelta = tmp_MilovoParam.GetActivitySlowKinetic() * (NumSoldArtifactsThisAgent - (CostRecipes * OldActivity));
	Mil_Double CurrentActivity = OldActivity + tmpDelta - (tmp_MilovoParam.GetLambdaActivity() * OldActivity);
	if(tmp_DebugLevel >= 2)
	{
		cout << "tmp_MilovoParam.GetLambdaActivity(): " << tmp_MilovoParam.GetLambdaActivity() << endl;
		cout << "tmp_MilovoParam.GetCostRecipes(): " << tmp_MilovoParam.GetCostRecipes() << endl;
		cout << "OldActivity: " << OldActivity << endl;
		cout << "SlowKinetic: " << tmp_MilovoParam.GetActivitySlowKinetic() << endl;
		cout << "NumSoldArtifactsThisAgent: " << NumSoldArtifactsThisAgent << "\tCostRecipes:" << CostRecipes << "\ttmpDelta: " << tmpDelta << endl;
		cout << "CurrentActivity: " << CurrentActivity << endl;
	}
	tmp_TabAgentsIter->second.SetActivity(CurrentActivity);
	if(tmp_TabAgentsIter->second.GetActivity() <= tmp_MilovoParam.GetActivityDeadLevel())
		FlagKillThisAgent = true;
	
	if(tmp_DebugLevel >= 1)
		cout << "CalcActivityThisAgent [end]" << endl;

	return(FlagKillThisAgent);
}

bool CheckForEvents(Events &tmp_TabEvents, Agents *tmp_TabAgents, Mil_Int tmp_IDAgentToAnalize, Recipes *tmp_TabRecipes, 
						  Artifacts *tmp_TabArtifacts, SystemParams &tmp_MilovoParam, MilovoEnvironment &tmp_MiloEnv)
{
	Agents::iterator tmpAgentSelectedIter = tmp_TabAgents->find(tmp_IDAgentToAnalize);
	if((tmp_MiloEnv.GetDebugLevel() >= 0) && (tmpAgentSelectedIter == tmp_TabAgents->end()))
	{
		cout << "Error in CheckForEvents function: cannot find an existing agent:" << tmpAgentSelectedIter->second.GetID() << endl;
		exit(EXIT_FAILURE);
	}
	if(tmp_MilovoParam.GetUseEvents() >= USE_EVENTS)
	{
		vector<Mil_Int> VectIDAgentOwnerArtifactsBornThisStep;
		for(Events::iterator tmp_TabEventsIter = tmp_TabEvents.begin(); tmp_TabEventsIter != tmp_TabEvents.end(); tmp_TabEventsIter++)
		{
			if((tmp_TabEventsIter->second.GetFlagExecute() == false) && 
				(tmp_TabEventsIter->second.GetEventStep() == tmp_MiloEnv.GetCurrentStep()) &&
				(tmp_TabEventsIter->second.GetEventCode() == 1))
			{
				vector<Mil_Int> VectAgentsAlive;
				GetAgentsAlive(VectAgentsAlive, tmp_TabAgents, tmp_MiloEnv.GetDebugLevel());
				VectAgentsAlive.push_back(0);
				for(vector<Mil_Int>::iterator VectAgentsAliveIter = VectAgentsAlive.begin(); VectAgentsAliveIter != VectAgentsAlive.end(); VectAgentsAliveIter++)
				{
					Mil_Int tmpIDAgentForNewFriendship = *VectAgentsAliveIter;
					if(tmpIDAgentForNewFriendship != tmpAgentSelectedIter->second.GetID())
					{
						bool FlagFriendFound = false;
						Relationships::iterator TabRelationshipsIter = tmpAgentSelectedIter->second.TabRelationships.begin();
						while((FlagFriendFound == false) && (TabRelationshipsIter != tmpAgentSelectedIter->second.TabRelationships.end()))
						{
							if(tmpIDAgentForNewFriendship == TabRelationshipsIter->second.GetIDAgentPartner())
								FlagFriendFound = true;
							TabRelationshipsIter++;
						}
						if(FlagFriendFound == false)
						{
							tmpAgentSelectedIter->second.TabRelationships.insert(make_pair(tmpIDAgentForNewFriendship, 
																												AgentRelationship(tmpIDAgentForNewFriendship)));
							//							cout << "Insert " << tmpIDAgentForNewFriendship << " for Ag: " << tmpAgentSelectedIter->second.GetID() << endl;
						}
					}
				}
			}
			// fiere
			if((tmp_TabEventsIter->second.GetFlagExecute() == false) && 
				(tmp_TabEventsIter->second.GetEventStep() == tmp_MiloEnv.GetCurrentStep()) &&
				(tmp_TabEventsIter->second.GetEventCode() == 2))
			{
				vector<Mil_Int> VectArtifactsBornThisStep;
				ExtractIDArtifactsBornThisStep(VectArtifactsBornThisStep, tmp_TabArtifacts, tmp_IDAgentToAnalize, tmp_TabAgents, 
														 tmp_MiloEnv.GetCurrentStep(), tmp_MiloEnv.GetDebugLevel());
				ExtractIDAgentOwnerArtifactsBornThisStep(VectIDAgentOwnerArtifactsBornThisStep, VectArtifactsBornThisStep, tmp_TabArtifacts, 
																	  tmp_MiloEnv.GetDebugLevel());
			}
		}
		ExtractIDArtifactsFromRelationshipsThisAgent(tmp_IDAgentToAnalize, tmp_TabAgents, tmp_TabRecipes, tmp_TabArtifacts, tmp_MiloEnv.GetDebugLevel());
		AddNewFriendsThisAgent(VectIDAgentOwnerArtifactsBornThisStep, tmp_IDAgentToAnalize, tmp_TabAgents, tmp_TabRecipes, tmp_TabArtifacts, 
									  tmp_MiloEnv.GetDebugLevel());
	}	

	return true;
}

bool InsertThisInputInTableRequests(Mil_Int tmpNameRequested, Requests *tmpCurrenTabRequests, Mil_Int tmpIDAgentOwner, MilovoEnvironment &tmp_CurrentMiloEnv)
{
	Mil_Int IDRequest = tmpCurrenTabRequests->size() + 1;
	tmpCurrenTabRequests->insert(make_pair(IDRequest, Request(IDRequest, tmpIDAgentOwner, tmpNameRequested, tmp_CurrentMiloEnv.GetCurrentStep())));
	
	return true;
}

vector<Mil_Int> GetRecipesThisAgentInRandomOrder(Agents *tmp_CurrentTabAgents, Mil_Int tmp_CurrentIDAgentToAnalize, MilovoRandom &tmp_CurrentMiloRand, 
																 MilovoEnvironment &tmp_CurrentMiloEnv)
{
	Agents::iterator tmp_CurrentTabAgentsIter = tmp_CurrentTabAgents->find(tmp_CurrentIDAgentToAnalize);
	if((tmp_CurrentMiloEnv.GetDebugLevel() >= 0) && (tmp_CurrentTabAgentsIter == tmp_CurrentTabAgents->end()))
	{
		cout << "Error in GetRecipesThisAgentInRandomOrder function: cannot found tmpCurrentTabAgentsIter in tmpCurrentTabAgents: " << tmp_CurrentIDAgentToAnalize << endl;
		exit(EXIT_FAILURE);
	}
	
	vector<Mil_Int> tmpVectRecipesRandomOrder;
	
	for(list<Mil_Int>::iterator LinkRecipesIter = tmp_CurrentTabAgentsIter->second.LinkRecipes.begin(); LinkRecipesIter != tmp_CurrentTabAgentsIter->second.LinkRecipes.end(); LinkRecipesIter++)
		tmpVectRecipesRandomOrder.push_back(*LinkRecipesIter);
	
	random_shuffle(tmpVectRecipesRandomOrder.begin(), tmpVectRecipesRandomOrder.end());
	
	return(tmpVectRecipesRandomOrder);
}


vector<Mil_Int> GetOrderRecipesThisAgent(Agents *tmpCurrentTabAgents, Mil_Int tmpCurrentIDAgentToAnalize, MilovoRandom &tmpCurrentMiloRand, 
																 MilovoEnvironment &tmpCurrentMiloEnv)
{
	Agents::iterator tmpCurrentTabAgentsIter = tmpCurrentTabAgents->find(tmpCurrentIDAgentToAnalize);
	if((tmpCurrentMiloEnv.GetDebugLevel() >= 0) && (tmpCurrentTabAgentsIter == tmpCurrentTabAgents->end()))
	{
		cout << "Error in GetRecipesThisAgentInRandomOrder function: cannot found tmpCurrentTabAgentsIter in tmpCurrentTabAgents: " << tmpCurrentIDAgentToAnalize << endl;
		exit(EXIT_FAILURE);
	}
	
	vector<Mil_Int> tmpVectRecipesRandomOrder;
	switch (tmpCurrentTabAgentsIter->second.Style.GetProduceRecipeMethod()) 
	{
		case 1:
		{
			for(list<Mil_Int>::iterator LinkRecipesIter = tmpCurrentTabAgentsIter->second.LinkRecipes.begin(); LinkRecipesIter != tmpCurrentTabAgentsIter->second.LinkRecipes.end(); LinkRecipesIter++)
				tmpVectRecipesRandomOrder.push_back(*LinkRecipesIter);
		}
			break;
		case 2:
		{
			tmpVectRecipesRandomOrder = GetRecipesThisAgentInRandomOrder(tmpCurrentTabAgents, tmpCurrentIDAgentToAnalize, tmpCurrentMiloRand, tmpCurrentMiloEnv);
		}
			break;
		case 3:
		{
			for(list<Mil_Int>::iterator LinkRecipesIter = tmpCurrentTabAgentsIter->second.LinkRecipes.begin(); LinkRecipesIter != tmpCurrentTabAgentsIter->second.LinkRecipes.end(); LinkRecipesIter++)
				tmpVectRecipesRandomOrder.insert(tmpVectRecipesRandomOrder.begin(), *LinkRecipesIter);
		}
			break;
		default:
			break;
	}
	
	return(tmpVectRecipesRandomOrder);
}

